home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / 92052tar.gz / 920528.tar / login.c < prev    next >
C/C++ Source or Header  |  1992-01-13  |  13KB  |  537 lines

  1. /* @(#) $Header: login.c,v 1.18 92/01/12 18:40:11 deyke Exp $ */
  2.  
  3. #include <sys/types.h>
  4.  
  5. #include <stdio.h>      /* must be before pwd.h */
  6.  
  7. #include <ctype.h>
  8. #include <fcntl.h>
  9. #include <pwd.h>
  10. #include <signal.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <sys/ptyio.h>
  14. #include <sys/rtprio.h>
  15. #include <sys/stat.h>
  16. #include <termio.h>
  17. #include <time.h>
  18. #include <unistd.h>
  19. #include <utmp.h>
  20.  
  21. #include "global.h"
  22. #include "mbuf.h"
  23. #include "timer.h"
  24. #include "hpux.h"
  25. #include "telnet.h"
  26. #include "login.h"
  27.  
  28. #define MASTERPREFIX        "/dev/pty"
  29. #define SLAVEPREFIX         "/dev/tty"
  30. #define NUMPTY              256
  31.  
  32. #define PASSWDFILE          "/etc/passwd"
  33. #define PWLOCKFILE          "/etc/ptmp"
  34.  
  35. #define DEFAULTUSER         "guest"
  36. #define FIRSTUID            400
  37. #define MAXUID              4095
  38. #define GID                 400
  39. #define HOMEDIRPARENTPARENT "/users/funk"
  40.  
  41. /* login server control block */
  42.  
  43. struct login_cb {
  44.   int  pty;                     /* pty file descriptor */
  45.   int  num;                     /* pty number */
  46.   char  id[4];                  /* pty id (last 2 chars) */
  47.   int  pid;                     /* process id of login process */
  48.   char  inpbuf[512];            /* pty read buffer */
  49.   char  *inpptr;                /* pty read buffer pointer */
  50.   int  inpcnt;                  /* pty read buffer count */
  51.   struct mbuf *sndq;            /* pty send queue */
  52.   int  lastchr;                 /* last chr fetched from send queue */
  53.   int  linelen;                 /* counter for automatic line break */
  54.   char  outbuf[256];            /* pty write buffer */
  55.   char  *outptr;                /* pty write buffer pointer */
  56.   int  outcnt;                  /* pty write buffer count */
  57.   void (*readfnc) __ARGS((void *fncarg));
  58.                 /* func to call if pty is readable */
  59.   void (*closefnc) __ARGS((void *fncarg));
  60.                 /* func to call if pty gets closed */
  61.   void  *fncarg;                /* argument for readfnc and closefnc */
  62.   int  telnet;                  /* telnet mode */
  63.   int  state;                   /* telnet state */
  64.   char  option[NOPTIONS+1];     /* telnet options */
  65. };
  66.  
  67. static int32 pty_locktime[NUMPTY];
  68.  
  69. static int find_pty __ARGS((int *numptr, char *slave));
  70. static void restore_pty __ARGS((char *id));
  71. static void write_log_header __ARGS((int fd, char *user, char *protocol));
  72. static int do_telnet __ARGS((struct login_cb *tp, int chr));
  73. static void write_pty __ARGS((struct login_cb *tp));
  74. static void excp_handler __ARGS((struct login_cb *tp));
  75.  
  76. /*---------------------------------------------------------------------------*/
  77.  
  78. #define pty_name(name, prefix, num) \
  79.   sprintf(name, "%s%c%x", prefix, 'p' + (num >> 4), num & 0xf)
  80.  
  81. /*---------------------------------------------------------------------------*/
  82.  
  83. static int find_pty(numptr, slave)
  84. int *numptr;
  85. char *slave;
  86. {
  87.  
  88.   char master[80];
  89.   int fd, num;
  90.  
  91.   for (num = 0; num < NUMPTY; num++)
  92.     if (pty_locktime[num] < secclock()) {
  93.       pty_locktime[num] = secclock() + 60;
  94.       pty_name(master, MASTERPREFIX, num);
  95.       if ((fd = open(master, O_RDWR | O_NDELAY, 0600)) >= 0) {
  96.     *numptr = num;
  97.     pty_name(slave, SLAVEPREFIX, num);
  98.     return fd;
  99.       }
  100.     }
  101.   return (-1);
  102. }
  103.  
  104. /*---------------------------------------------------------------------------*/
  105.  
  106. static void restore_pty(id)
  107. char  *id;
  108. {
  109.   char  filename[80];
  110.  
  111.   sprintf(filename, "%s%s", MASTERPREFIX, id);
  112.   chown(filename, 0, 0);
  113.   chmod(filename, 0666);
  114.   sprintf(filename, "%s%s", SLAVEPREFIX, id);
  115.   chown(filename, 0, 0);
  116.   chmod(filename, 0666);
  117. }
  118.  
  119. /*---------------------------------------------------------------------------*/
  120.  
  121. void fixutmpfile()
  122. {
  123.   register struct utmp *up;
  124.  
  125.   while (up = getutent())
  126.     if (up->ut_type == USER_PROCESS && kill(up->ut_pid, 0)) {
  127.       restore_pty(up->ut_id);
  128.       up->ut_user[0] = '\0';
  129.       up->ut_type = DEAD_PROCESS;
  130.       up->ut_exit.e_termination = 0;
  131.       up->ut_exit.e_exit = 0;
  132.       up->ut_time = secclock();
  133.       pututline(up);
  134.     }
  135.   endutent();
  136. }
  137.  
  138. /*---------------------------------------------------------------------------*/
  139.  
  140. struct passwd *getpasswdentry(name, create)
  141. char  *name;
  142. int  create;
  143. {
  144.  
  145.   FILE * fp;
  146.   char  *cp;
  147.   char  bitmap[MAXUID+1];
  148.   char  homedir[80];
  149.   char  homedirparent[80];
  150.   char  username[128];
  151.   int  fd;
  152.   int  uid;
  153.   struct passwd *pw;
  154.  
  155.   /* Fix user name */
  156.  
  157.   for (cp = username; isalnum(uchar(*name)); *cp++ = tolower(uchar(*name++))) ;
  158.   *cp = '\0';
  159.   if (!isalpha(uchar(*username)) || strlen(username) > 8)
  160.     strcpy(username, DEFAULTUSER);
  161.  
  162.   /* Search existing passwd entry */
  163.  
  164.   while ((pw = getpwent()) && strcmp(username, pw->pw_name)) ;
  165.   endpwent();
  166.   if (pw) return pw;
  167.   if (!create) return 0;
  168.  
  169.   /* Find free user id */
  170.  
  171.   if ((fd = open(PWLOCKFILE, O_WRONLY | O_CREAT | O_EXCL, 0644)) < 0) return 0;
  172.   close(fd);
  173.   memset(bitmap, 0, sizeof(bitmap));
  174.   while (pw = getpwent()) {
  175.     if (!strcmp(username, pw->pw_name)) break;
  176.     if (pw->pw_uid <= MAXUID) bitmap[pw->pw_uid] = 1;
  177.   }
  178.   endpwent();
  179.   if (pw) {
  180.     unlink(PWLOCKFILE);
  181.     return pw;
  182.   }
  183.   for (uid = FIRSTUID; uid <= MAXUID && bitmap[uid]; uid++) ;
  184.   if (uid > MAXUID) {
  185.     unlink(PWLOCKFILE);
  186.     return 0;
  187.   }
  188.  
  189.   /* Add user to passwd file */
  190.  
  191.   sprintf(homedirparent, "%s/%.3s...", HOMEDIRPARENTPARENT, username);
  192.   sprintf(homedir, "%s/%s", homedirparent, username);
  193.   if (!(fp = fopen(PASSWDFILE, "a"))) {
  194.     unlink(PWLOCKFILE);
  195.     return 0;
  196.   }
  197.   fprintf(fp, "%s:,./:%d:%d::%s:/bin/sh\n", username, uid, GID, homedir);
  198.   fclose(fp);
  199.   pw = getpwuid(uid);
  200.   endpwent();
  201.   unlink(PWLOCKFILE);
  202.  
  203.   /* Create home directory */
  204.  
  205.   mkdir(homedirparent, 0755);
  206.   mkdir(homedir, 0755);
  207.   chown(homedir, uid, GID);
  208.   return pw;
  209. }
  210.  
  211. /*---------------------------------------------------------------------------*/
  212.  
  213. static void write_log_header(fd, user, protocol)
  214. int  fd;
  215. char  *user, *protocol;
  216. {
  217.  
  218.   char  buf[1024];
  219.   struct tm *tm;
  220.  
  221.   tm = localtime((long *) &Secclock);
  222.   sprintf(buf,
  223.       "%s at %2d-%.3s-%02d %2d:%02d:%02d by %s\n",
  224.       protocol,
  225.       tm->tm_mday,
  226.       "JanFebMarAprMayJunJulAugSepOctNovDec" + 3 * tm->tm_mon,
  227.       tm->tm_year % 100,
  228.       tm->tm_hour,
  229.       tm->tm_min,
  230.       tm->tm_sec,
  231.       user);
  232.   write_log(fd, buf, (int) strlen(buf));
  233. }
  234.  
  235. /*---------------------------------------------------------------------------*/
  236.  
  237. static int  do_telnet(tp, chr)
  238. struct login_cb *tp;
  239. int  chr;
  240. {
  241.   struct termio termio;
  242.  
  243.   switch (tp->state) {
  244.   case TS_DATA:
  245.     if (chr != IAC) {
  246.       /*** if (!tp->option[TN_TRANSMIT_BINARY]) chr &= 0x7f; ***/
  247.       return 1;
  248.     }
  249.     tp->state = TS_IAC;
  250.     break;
  251.   case TS_IAC:
  252.     switch (chr) {
  253.     case WILL:
  254.       tp->state = TS_WILL;
  255.       break;
  256.     case WONT:
  257.       tp->state = TS_WONT;
  258.       break;
  259.     case DO:
  260.       tp->state = TS_DO;
  261.       break;
  262.     case DONT:
  263.       tp->state = TS_DONT;
  264.       break;
  265.     case IAC:
  266.       tp->state = TS_DATA;
  267.       return 1;
  268.     default:
  269.       tp->state = TS_DATA;
  270.       break;
  271.     }
  272.     break;
  273.   case TS_WILL:
  274.     tp->state = TS_DATA;
  275.     break;
  276.   case TS_WONT:
  277.     tp->state = TS_DATA;
  278.     break;
  279.   case TS_DO:
  280.     if (chr <= NOPTIONS) tp->option[chr] = 1;
  281.     if (chr == TN_ECHO) {
  282.       ioctl(tp->pty, TCGETA, &termio);
  283.       termio.c_lflag |= (ECHO | ECHOE);
  284.       ioctl(tp->pty, TCSETA, &termio);
  285.     }
  286.     tp->state = TS_DATA;
  287.     break;
  288.   case TS_DONT:
  289.     if (chr <= NOPTIONS) tp->option[chr] = 0;
  290.     if (chr == TN_ECHO) {
  291.       ioctl(tp->pty, TCGETA, &termio);
  292.       termio.c_lflag &= ~(ECHO | ECHOE);
  293.       ioctl(tp->pty, TCSETA, &termio);
  294.     }
  295.     tp->state = TS_DATA;
  296.     break;
  297.   }
  298.   return 0;
  299. }
  300.  
  301. /*---------------------------------------------------------------------------*/
  302.  
  303. static void write_pty(tp)
  304. struct login_cb *tp;
  305. {
  306.  
  307.   char *p;
  308.   int chr;
  309.   int lastchr;
  310.   int n;
  311.  
  312.   if (!tp->outcnt) {
  313.     p = tp->outbuf;
  314.     while ((chr = PULLCHAR(&tp->sndq)) != -1) {
  315.       lastchr = tp->lastchr;
  316.       tp->lastchr = chr;
  317.       if (!tp->telnet || do_telnet(tp, uchar(chr))) {
  318.     if (lastchr != '\r' || chr != '\0' && chr != '\n') {
  319.       *p++ = chr;
  320.       if (chr == '\r' || chr == '\n') {
  321.         tp->linelen = 0;
  322.         break;
  323.       }
  324.       if (++tp->linelen >= 250) {
  325.         *p++ = '\n';
  326.         tp->linelen = 0;
  327.         break;
  328.       }
  329.     }
  330.       }
  331.     }
  332.     tp->outptr = tp->outbuf;
  333.     tp->outcnt = p - tp->outbuf;
  334.   }
  335.   if (tp->outcnt) {
  336.     n = write(tp->pty, tp->outptr, tp->outcnt);
  337.     if (n < 0) n = 0;
  338.     if (n) write_log(tp->pty, tp->outptr, n);
  339.     tp->outptr += n;
  340.     tp->outcnt -= n;
  341.   }
  342.   if (!tp->outcnt && !tp->sndq) off_write(tp->pty);
  343. }
  344.  
  345. /*---------------------------------------------------------------------------*/
  346.  
  347. static void excp_handler(tp)
  348. struct login_cb *tp;
  349. {
  350.   struct request_info request_info;
  351.  
  352.   if (ioctl(tp->pty, TIOCREQCHECK, &request_info)) return;
  353.   ioctl(tp->pty, TIOCREQSET, &request_info);
  354.   if (request_info.request == TIOCCLOSE) {
  355.     off_read(tp->pty);
  356.     off_write(tp->pty);
  357.     off_excp(tp->pty);
  358.     if (tp->closefnc) (*tp->closefnc)(tp->fncarg);
  359.   }
  360. }
  361.  
  362. /*---------------------------------------------------------------------------*/
  363.  
  364. struct login_cb *login_open(user, protocol, read_upcall, close_upcall, upcall_arg)
  365. char  *user, *protocol;
  366. void (*read_upcall) __ARGS((void *arg));
  367. void (*close_upcall) __ARGS((void *arg));
  368. void  *upcall_arg;
  369. {
  370.  
  371.   char  *env = 0;
  372.   char  slave[80];
  373.   int  i;
  374.   struct login_cb *tp;
  375.   struct passwd *pw;
  376.   struct termio termio;
  377.   struct utmp utmp;
  378.  
  379.   tp = (struct login_cb *) calloc(1, sizeof(struct login_cb ));
  380.   if (!tp) return 0;
  381.   tp->telnet = !strcmp(protocol, "TELNET");
  382.   if ((tp->pty = find_pty(&tp->num, slave)) < 0) {
  383.     free(tp);
  384.     return 0;
  385.   }
  386.   strcpy(tp->id, slave + strlen(slave) - 2);
  387.   tp->readfnc = read_upcall;
  388.   tp->closefnc = close_upcall;
  389.   tp->fncarg = upcall_arg;
  390.   on_read(tp->pty, tp->readfnc, tp->fncarg);
  391.   on_excp(tp->pty, (void (*)()) excp_handler, tp);
  392.   i = 1;
  393.   ioctl(tp->pty, TIOCTRAP, &i);
  394.   write_log_header(tp->pty, user, protocol);
  395.   if (!(tp->pid = fork())) {
  396.     rtprio(0, RTPRIO_RTOFF);
  397.     pw = getpasswdentry(user, 1);
  398.     if (!pw || pw->pw_passwd[0]) pw = getpasswdentry("", 0);
  399.     for (i = 0; i < _NFILE; i++) close(i);
  400.     setpgrp();
  401.     open(slave, O_RDWR, 0666);
  402.     dup(0);
  403.     dup(0);
  404.     chmod(slave, 0622);
  405.     memset(&termio, 0, sizeof(termio));
  406.     termio.c_iflag = ICRNL | IXOFF;
  407.     termio.c_oflag = OPOST | ONLCR | TAB3;
  408.     termio.c_cflag = B1200 | CS8 | CREAD | CLOCAL;
  409.     termio.c_lflag = ISIG | ICANON;
  410.     termio.c_cc[VINTR]  = 127;
  411.     termio.c_cc[VQUIT]  =  28;
  412.     termio.c_cc[VERASE] =   8;
  413.     termio.c_cc[VKILL]  =  24;
  414.     termio.c_cc[VEOF]   =   4;
  415.     ioctl(0, TCSETA, &termio);
  416.     ioctl(0, TCFLSH, 2);
  417.     if (!pw || pw->pw_passwd[0]) exit(1);
  418.     memset(&utmp, 0, sizeof(utmp));
  419.     strcpy(utmp.ut_user, "LOGIN");
  420.     strcpy(utmp.ut_id, tp->id);
  421.     strcpy(utmp.ut_line, slave + 5);
  422.     utmp.ut_pid = getpid();
  423.     utmp.ut_type = LOGIN_PROCESS;
  424.     utmp.ut_time = secclock();
  425. #ifdef _UTMP_INCLUDED   /* for HP-UX 6.5 compatibility */
  426.     strncpy(utmp.ut_host, protocol, sizeof(utmp.ut_host));
  427. #endif
  428.     pututline(&utmp);
  429.     endutent();
  430.     execle("/bin/login", "login", pw->pw_name, (char *) 0, &env);
  431.     exit(1);
  432.   }
  433.   return tp;
  434. }
  435.  
  436. /*---------------------------------------------------------------------------*/
  437.  
  438. void login_close(tp)
  439. struct login_cb *tp;
  440. {
  441.  
  442.   int  fwtmp;
  443.   struct utmp utmp, *up;
  444.  
  445.   if (!tp) return;
  446.   if (tp->pty > 0) {
  447.     off_read(tp->pty);
  448.     off_write(tp->pty);
  449.     off_excp(tp->pty);
  450.     close(tp->pty);
  451.     restore_pty(tp->id);
  452.     pty_locktime[tp->num] = 0;
  453.     write_log(tp->pty, (char *) 0, -1);
  454.   }
  455.   if (tp->pid > 0) {
  456.     kill(-tp->pid, SIGHUP);
  457.     memset(&utmp, 0, sizeof(utmp));
  458.     strcpy(utmp.ut_id, tp->id);
  459.     utmp.ut_type = DEAD_PROCESS;
  460.     if (up = getutid(&utmp)) {
  461.       up->ut_user[0] = '\0';
  462.       up->ut_type = DEAD_PROCESS;
  463.       up->ut_exit.e_termination = 0;
  464.       up->ut_exit.e_exit = 0;
  465.       up->ut_time = secclock();
  466.       memcpy(&utmp, up, sizeof(utmp));
  467.       pututline(up);
  468.       fwtmp = open("/etc/wtmp", O_WRONLY | O_CREAT | O_APPEND, 0644);
  469.       write(fwtmp, (char *) &utmp, sizeof(utmp));
  470.       close(fwtmp);
  471.     }
  472.     endutent();
  473.   }
  474.   free_q(&tp->sndq);
  475.   free(tp);
  476. }
  477.  
  478. /*---------------------------------------------------------------------------*/
  479.  
  480. #define ASIZE 512
  481.  
  482. #define add_to_mbuf(chr) \
  483. { \
  484.   if (!head) head = tail = alloc_mbuf(ASIZE); \
  485.   if (tail->cnt >= ASIZE) tail = tail->next = alloc_mbuf(ASIZE); \
  486.   tail->data[tail->cnt++] = chr; \
  487.   cnt--; \
  488. }
  489.  
  490. /*---------------------------------------------------------------------------*/
  491.  
  492. struct mbuf *login_read(tp, cnt)
  493. struct login_cb *tp;
  494. int  cnt;
  495. {
  496.  
  497.   int  chr;
  498.   struct mbuf *head, *tail;
  499.  
  500.   if (cnt <= 0) {
  501.     off_read(tp->pty);
  502.     return 0;
  503.   }
  504.   on_read(tp->pty, tp->readfnc, tp->fncarg);
  505.   head = 0;
  506.   while (cnt) {
  507.     if (tp->inpcnt <= 0) {
  508.       if ((tp->inpcnt = read(tp->pty, tp->inpptr = tp->inpbuf, sizeof(tp->inpbuf))) <= 0)
  509.     return head;
  510.       write_log(tp->pty, tp->inpbuf, tp->inpcnt);
  511.     }
  512.     tp->inpcnt--;
  513.     chr = uchar(*tp->inpptr++);
  514.     if (chr == 0x11 || chr == 0x13) {
  515.       /* ignore XON / XOFF */
  516.     } else if (tp->telnet) {
  517.       add_to_mbuf(chr);
  518.       if (chr == IAC) add_to_mbuf(IAC);
  519.     } else {
  520.       if (chr != '\n') add_to_mbuf(chr);
  521.     }
  522.   }
  523.   return head;
  524. }
  525.  
  526. /*---------------------------------------------------------------------------*/
  527.  
  528. void login_write(tp, bp)
  529. struct login_cb *tp;
  530. struct mbuf *bp;
  531. {
  532.   append(&tp->sndq, bp);
  533.   on_write(tp->pty, (void (*)()) write_pty, tp);
  534.   if (tp->linelen) write_pty(tp);
  535. }
  536.  
  537.